using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using System.IO;
using Base;
namespace Terrain
{
    public class TerrainController : DrawableGameComponent, ITerrainController
    {
        public struct VertexMultitextured
        {
            public Vector3 Position;
            public Vector3 Normal;
            public Vector4 TextureCoordinate;
            public Vector4 TexWeights;

            public static int SizeInBytes = (3 + 3 + 4 + 4) * 4;
            public static VertexElement[] VertexElements = new VertexElement[]
              {
                  new VertexElement( 0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0 ),
                  new VertexElement( 0, sizeof(float) * 3, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0 ),
                  new VertexElement( 0, sizeof(float) * 6, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0 ),
                  new VertexElement( 0, sizeof(float) * 10, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 1 ),
              };
        }

        public VertexMultitextured[] terrainVertices;
        private Effect effect;
        private VertexBuffer terrainVertexBuffer;
        private IndexBuffer terrainIndexBuffer;
        Texture2D heightMap;
        public int WIDTH;
        public int HEIGHT;
        public float[,] heightData;
        private Texture2D sandTexture;
        private Texture2D grassTexture;
        private Texture2D rockTexture;
        private Texture2D snowTexture;
        private Model skyDome;
        private Texture2D skyDomeTexture;
        private RenderTarget2D refractionRenderTarg;
        private Texture2D refractionMap;
        private RenderTarget2D reflectionRenderTarg;
        private Texture2D reflectionMap;
        private float waterHeight = 5.0f;
        private Matrix reflectionViewMatrix;
        private VertexPositionTexture[] waterVertices;
        private Texture2D waterBumpMap;
        Vector3[,] terrainNormals;
        private float elapsedTime;
        public bool drawTerrain = true;
        public bool drawSkyBox = true;
        public bool drawReflection = true;
        public bool drawRefraction = true;

        public TerrainController(Game game)
            : base(game)
        {
        }

        protected override void LoadContent()
        {
            SetUpXNADevice();


            heightMap = base.Game.Content.Load<Texture2D>("Terrain\\heightmap");
            sandTexture = base.Game.Content.Load<Texture2D>("Terrain\\sand");
            grassTexture = base.Game.Content.Load<Texture2D>("Terrain\\grass");
            rockTexture = base.Game.Content.Load<Texture2D>("Terrain\\rock");
            snowTexture = base.Game.Content.Load<Texture2D>("Terrain\\snow");
            LoadSkyDome();
            waterBumpMap = base.Game.Content.Load<Texture2D>("Terrain\\waterbump");


            LoadHeightData();

            SetUpTerrainVertices();
            SetUpTerrainIndices();
            SetInitialValues();
            SetUpWaterVertices();

            terrainNormals = new Vector3[WIDTH, HEIGHT];
            for (int x = 1; x < WIDTH - 1; x++)
            {
                for (int y = 1; y < HEIGHT - 1; y++)
                {
                    terrainNormals[x, y] = terrainVertices[x + y * WIDTH].Normal;
                }
            }


        }
        public Matrix ReflectionViewMatrix
        {
            get
            {
                return reflectionViewMatrix;
            }
        }
        public float MinHeight
        {
            get
            {
                return waterHeight;
            }
        }
        public Vector3 GetNormal(int X, int Z)
        {
            return terrainNormals[Z, X];
        }

        public float GetTerrainHeight(float fTerX, float fTerY)
        {
            // we first get the height of 4 points of the quad underneath the point
            float temp = fTerY;
            fTerY = fTerX;
            fTerX = temp;
            int x = (int)fTerX;
            int y = (int)fTerY;

            if (x >= 0 && x <= HEIGHT - 2
                && y >= 0 && y <= WIDTH - 2)
            {

                float fTriY0 = (heightData[x, y]);
                float fTriY1 = (heightData[x + 1, y]);
                float fTriY2 = (heightData[x, y + 1]);
                float fTriY3 = (heightData[x + 1, y + 1]);
                // find which of the 2 triangles the point is over (depends on how you render)
                // then take the height at a triangle point
                // and adjust by the slope down right-angle edges * distance along that edge.
                float fHeight;
                float fSqX = fTerX - x;
                float fSqY = fTerY - y;
                if ((fSqX + fSqY) < 1)
                {
                    fHeight = fTriY0;
                    fHeight += (fTriY1 - fTriY0) * fSqX;
                    fHeight += (fTriY2 - fTriY0) * fSqY;
                }
                else
                {
                    fHeight = fTriY3;
                    fHeight += (fTriY1 - fTriY3) * (1.0f - fSqY);
                    fHeight += (fTriY2 - fTriY3) * (1.0f - fSqX);
                }
                return fHeight;
            }
            return 0.0f;
        }

        private void SetInitialValues()
        {

            refractionRenderTarg = new RenderTarget2D(base.GraphicsDevice, 512, 512, 1, SurfaceFormat.Color
                , 0, 0);
            reflectionRenderTarg = new RenderTarget2D(base.GraphicsDevice, 512, 512, 1, SurfaceFormat.Color, 0, 0);
        }

        private void SetUpXNADevice()
        {
            effect = base.Game.Content.Load<Effect>("Terrain\\Series4Effects");
        }

        private void SetUpTerrainVertices()
        {
            terrainVertices = new VertexMultitextured[WIDTH * HEIGHT];

            for (int x = 0; x < WIDTH; x++)
                for (int y = 0; y < HEIGHT; y++)
                {
                    terrainVertices[x + y * WIDTH].Position = new Vector3(x, y, heightData[x, y]);
                    terrainVertices[x + y * WIDTH].Normal = new Vector3(0, 0, 1);
                    terrainVertices[x + y * WIDTH].TextureCoordinate.X = (float)x / 30.0f;
                    terrainVertices[x + y * WIDTH].TextureCoordinate.Y = (float)y / 30.0f;

                    terrainVertices[x + y * WIDTH].TexWeights.X = MathHelper.Clamp(1.0f - Math.Abs(heightData[x, y] - 0) / 8.0f, 0, 1);
                    terrainVertices[x + y * WIDTH].TexWeights.Y = MathHelper.Clamp(1.0f - Math.Abs(heightData[x, y] - 12) / 6.0f, 0, 1);
                    terrainVertices[x + y * WIDTH].TexWeights.Z = MathHelper.Clamp(1.0f - Math.Abs(heightData[x, y] - 20) / 6.0f, 0, 1);
                    terrainVertices[x + y * WIDTH].TexWeights.W = MathHelper.Clamp(1.0f - Math.Abs(heightData[x, y] - 30) / 6.0f, 0, 1);

                    float totalWeight = terrainVertices[x + y * WIDTH].TexWeights.X;
                    totalWeight += terrainVertices[x + y * WIDTH].TexWeights.Y;
                    totalWeight += terrainVertices[x + y * WIDTH].TexWeights.Z;
                    totalWeight += terrainVertices[x + y * WIDTH].TexWeights.W;
                    terrainVertices[x + y * WIDTH].TexWeights.X /= totalWeight;
                    terrainVertices[x + y * WIDTH].TexWeights.Y /= totalWeight;
                    terrainVertices[x + y * WIDTH].TexWeights.Z /= totalWeight;
                    terrainVertices[x + y * WIDTH].TexWeights.W /= totalWeight;
                }

            for (int x = 1; x < WIDTH - 1; x++)
            {
                for (int y = 1; y < HEIGHT - 1; y++)
                {
                    Vector3 normX = new Vector3((terrainVertices[x - 1 + y * WIDTH].Position.Z - terrainVertices[x + 1 + y * WIDTH].Position.Z) / 2, 0, 1);
                    Vector3 normY = new Vector3(0, (terrainVertices[x + (y - 1) * WIDTH].Position.Z - terrainVertices[x + (y + 1) * WIDTH].Position.Z) / 2, 1);
                    terrainVertices[x + y * WIDTH].Normal = normX + normY;
                    terrainVertices[x + y * WIDTH].Normal.Normalize();
                }
            }

            terrainVertexBuffer = new VertexBuffer(base.GraphicsDevice, VertexMultitextured.SizeInBytes * WIDTH * HEIGHT, BufferUsage.WriteOnly);
            terrainVertexBuffer.SetData(terrainVertices);
        }

        private void SetUpTerrainIndices()
        {
            int[] terrainIndices = new int[(WIDTH - 1) * (HEIGHT - 1) * 6];
            for (int x = 0; x < WIDTH - 1; x++)
            {
                for (int y = 0; y < HEIGHT - 1; y++)
                {
                    terrainIndices[(x + y * (WIDTH - 1)) * 6] = (x + 1) + (y + 1) * WIDTH;
                    terrainIndices[(x + y * (WIDTH - 1)) * 6 + 1] = (x + 1) + y * WIDTH;
                    terrainIndices[(x + y * (WIDTH - 1)) * 6 + 2] = x + y * WIDTH;

                    terrainIndices[(x + y * (WIDTH - 1)) * 6 + 3] = (x + 1) + (y + 1) * WIDTH;
                    terrainIndices[(x + y * (WIDTH - 1)) * 6 + 4] = x + y * WIDTH;
                    terrainIndices[(x + y * (WIDTH - 1)) * 6 + 5] = x + (y + 1) * WIDTH;
                }
            }

            terrainIndexBuffer = new IndexBuffer(base.GraphicsDevice, typeof(int), (WIDTH - 1) * (HEIGHT - 1) * 6, BufferUsage.WriteOnly);
            terrainIndexBuffer.SetData(terrainIndices);
        }

        private void LoadHeightData()
        {
            float minimumHeight = 255;
            float maximumHeight = 0;

            WIDTH = heightMap.Width;
            HEIGHT = heightMap.Height;
            Color[] heightMapColors = new Color[WIDTH * HEIGHT];
            heightMap.GetData(heightMapColors);

            heightData = new float[WIDTH, HEIGHT];
            for (int x = 0; x < WIDTH; x++)
                for (int y = 0; y < HEIGHT; y++)
                {
                    heightData[x, y] = heightMapColors[x + y * WIDTH].R;
                    if (heightData[x, y] < minimumHeight) minimumHeight = heightData[x, y];
                    if (heightData[x, y] > maximumHeight) maximumHeight = heightData[x, y];
                }

            for (int x = 0; x < WIDTH; x++)
                for (int y = 0; y < HEIGHT; y++)
                    heightData[x, y] = (heightData[x, y] - minimumHeight) / (maximumHeight - minimumHeight) * 30;
        }



        private void SetUpWaterVertices()
        {
            waterVertices = new VertexPositionTexture[6];

            waterVertices[0] = new VertexPositionTexture(new Vector3(0, 0, waterHeight), new Vector2(0, 1));
            waterVertices[2] = new VertexPositionTexture(new Vector3(WIDTH, HEIGHT, waterHeight), new Vector2(1, 0));
            waterVertices[1] = new VertexPositionTexture(new Vector3(0, HEIGHT, waterHeight), new Vector2(0, 0));

            waterVertices[3] = new VertexPositionTexture(new Vector3(0, 0, waterHeight), new Vector2(0, 1));
            waterVertices[5] = new VertexPositionTexture(new Vector3(WIDTH, 0, waterHeight), new Vector2(1, 1));
            waterVertices[4] = new VertexPositionTexture(new Vector3(WIDTH, HEIGHT, waterHeight), new Vector2(1, 0));
        }

        private void LoadSkyDome()
        {

            skyDome = base.Game.Content.Load<Model>("Terrain\\dome");

            foreach (ModelMesh mesh in skyDome.Meshes)
                foreach (BasicEffect currenteffect in mesh.Effects)
                    skyDomeTexture = currenteffect.Texture;

            foreach (ModelMesh modmesh in skyDome.Meshes)
                foreach (ModelMeshPart modmeshpart in modmesh.MeshParts)
                    modmeshpart.Effect = effect.Clone(base.GraphicsDevice);
        }



        public override void Update(GameTime gameTime)
        {

        }




        private void DrawTerrain(Matrix currentViewMatrix, ICameraService camera)
        {
            effect.CurrentTechnique = effect.Techniques["MultiTextured"];
            effect.Parameters["xSandTexture"].SetValue(sandTexture);
            effect.Parameters["xGrassTexture"].SetValue(grassTexture);
            effect.Parameters["xRockTexture"].SetValue(rockTexture);
            effect.Parameters["xSnowTexture"].SetValue(snowTexture);

            Matrix worldMatrix = Matrix.Identity;
            effect.Parameters["xWorld"].SetValue(worldMatrix * Matrix.CreateRotationX(-(float)Math.PI / 2) * Matrix.CreateRotationY(-(float)Math.PI / 2));
            effect.Parameters["xView"].SetValue(currentViewMatrix);
            effect.Parameters["xProjection"].SetValue(camera.ProjectionMatrix);
            effect.Parameters["xEnableLighting"].SetValue(true);
            effect.Parameters["xLightDirection"].SetValue(new Vector3(20.0f, 15.0f, 20.0f));
            effect.Parameters["xAmbient"].SetValue(0.7f);

            effect.Begin();
            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Begin();

                base.GraphicsDevice.Vertices[0].SetSource(terrainVertexBuffer, 0, VertexMultitextured.SizeInBytes);
                base.GraphicsDevice.Indices = terrainIndexBuffer;
                base.GraphicsDevice.VertexDeclaration = new VertexDeclaration(base.GraphicsDevice, VertexMultitextured.VertexElements);

                base.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, WIDTH * HEIGHT, 0, (WIDTH - 1) * (HEIGHT - 1) * 2);

                pass.End();
            }
            effect.End();
        }

        private void DrawSkyDome(Matrix currentViewMatrix, ICameraService camera)
        {
            foreach (ModelMesh modmesh in skyDome.Meshes)
            {
                foreach (Effect currenteffect in modmesh.Effects)
                {
                    currenteffect.CurrentTechnique = effect.Techniques["Textured"];
                    Matrix worldMatrix = Matrix.CreateScale(750, 750, 750) * Matrix.CreateTranslation(camera.Position - new Vector3(0, 200, 0)) * Matrix.CreateRotationX(-(float)Math.PI / 2) * Matrix.CreateRotationY(-(float)Math.PI / 2);
                    currenteffect.Parameters["xWorld"].SetValue(worldMatrix);
                    currenteffect.Parameters["xView"].SetValue(currentViewMatrix);
                    currenteffect.Parameters["xProjection"].SetValue(camera.ProjectionMatrix);
                    currenteffect.Parameters["xTexture"].SetValue(skyDomeTexture);
                }
                modmesh.Draw();
            }
        }

        private void DrawRefractionMap(ICameraService camera)
        {
            Vector3 planeNormalDirection = new Vector3(0, -1, 0);
            planeNormalDirection.Normalize();
            Vector4 planeCoefficients = new Vector4(planeNormalDirection, waterHeight + 1.0f);

            Matrix camMatrix = camera.ViewMatrix * camera.ProjectionMatrix;
            Matrix invCamMatrix = Matrix.Invert(camMatrix);
            invCamMatrix = Matrix.Transpose(invCamMatrix);

            planeCoefficients = Vector4.Transform(planeCoefficients, invCamMatrix);
            Plane refractionClipPlane = new Plane(planeCoefficients);

            base.GraphicsDevice.ClipPlanes[0].Plane = refractionClipPlane;
            base.GraphicsDevice.ClipPlanes[0].IsEnabled = true;

            base.GraphicsDevice.SetRenderTarget(0, refractionRenderTarg);
            DepthStencilBuffer temp = base.GraphicsDevice.DepthStencilBuffer;
            base.GraphicsDevice.DepthStencilBuffer = new DepthStencilBuffer(base.GraphicsDevice, 512, 512, DepthFormat.Depth16, 0, 0);
            base.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1.0f, 0);
            if (drawTerrain)
            {
                DrawTerrain(camera.ViewMatrix, camera);
            }

            base.GraphicsDevice.SetRenderTarget(0, null);
            refractionMap = refractionRenderTarg.GetTexture();
            base.GraphicsDevice.DepthStencilBuffer = temp;

            base.GraphicsDevice.ClipPlanes[0].IsEnabled = false;
        }

        private void DrawReflectionMap(ICameraService camera)
        {
            IEntityController entities = (IEntityController)base.Game.Services.GetService(typeof(IEntityController));

            Vector3 planeNormalDirection = new Vector3(0, 1, 0);
            planeNormalDirection.Normalize();
            Vector4 planeCoefficients = new Vector4(planeNormalDirection, -waterHeight);

            Matrix camMatrix = reflectionViewMatrix * camera.ProjectionMatrix;
            Matrix invCamMatrix = Matrix.Invert(camMatrix);
            invCamMatrix = Matrix.Transpose(invCamMatrix);

            planeCoefficients = Vector4.Transform(planeCoefficients, invCamMatrix);
            Plane reflectionClipPlane = new Plane(planeCoefficients);

            base.GraphicsDevice.ClipPlanes[0].Plane = reflectionClipPlane;
            base.GraphicsDevice.ClipPlanes[0].IsEnabled = true;

            DepthStencilBuffer temp = base.GraphicsDevice.DepthStencilBuffer;
            base.GraphicsDevice.DepthStencilBuffer = new DepthStencilBuffer(base.GraphicsDevice, 512, 512, DepthFormat.Depth16, 0, 0);
            base.GraphicsDevice.SetRenderTarget(0, reflectionRenderTarg);
            base.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1.0f, 0);
            if (drawTerrain)
            {
                DrawTerrain(reflectionViewMatrix,camera);
            }
            if (drawSkyBox)
            {
                DrawSkyDome(reflectionViewMatrix, camera);
            }
            entities.Draw(true);
            base.GraphicsDevice.SetRenderTarget(0, null);
            reflectionMap = reflectionRenderTarg.GetTexture();
            base.GraphicsDevice.DepthStencilBuffer = temp;

            base.GraphicsDevice.ClipPlanes[0].IsEnabled = false;
        }

        private void DrawWater(ICameraService camera)
        {
            effect.CurrentTechnique = effect.Techniques["Water"];
            Matrix worldMatrix = Matrix.Identity;
            effect.Parameters["xWorld"].SetValue(worldMatrix * Matrix.CreateRotationX(-(float)Math.PI / 2) * Matrix.CreateRotationY(-(float)Math.PI / 2));
            effect.Parameters["xView"].SetValue(camera.ViewMatrix);
            effect.Parameters["xReflectionView"].SetValue(reflectionViewMatrix);
            effect.Parameters["xProjection"].SetValue(camera.ProjectionMatrix);

            effect.Parameters["xReflectionMap"].SetValue(reflectionMap);
            effect.Parameters["xRefractionMap"].SetValue(refractionMap);
            effect.Parameters["xWaterBumpMap"].SetValue(waterBumpMap);
            effect.Parameters["xWaveLength"].SetValue(0.1f);
            effect.Parameters["xWaveHeight"].SetValue(0.3f);
            effect.Parameters["xCamPos"].SetValue(camera.Position);

            effect.Parameters["xTime"].SetValue(elapsedTime);
            effect.Parameters["xWindForce"].SetValue(20.0f);
            Matrix windDirection = Matrix.CreateRotationZ(MathHelper.PiOver2);
            effect.Parameters["xWindDirection"].SetValue(windDirection);


            effect.Begin();
            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Begin();
                base.GraphicsDevice.VertexDeclaration = new VertexDeclaration(base.GraphicsDevice, VertexPositionTexture.VertexElements);
                base.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, waterVertices, 0, 2);
                pass.End();
            }
            effect.End();


            //SpriteBatch batch = new SpriteBatch(device);
            //batch.Begin();
            //batch.Draw(refractionMap, new Rectangle(0, 0, WIDTH * 2, HEIGHT * 2), null, Color.White);
            //batch.End();
        }

        public override void Draw(GameTime gameTime)
        {
            ICameraService camera = (ICameraService)base.Game.Services.GetService(typeof(ICameraService));
            elapsedTime += (float)gameTime.ElapsedGameTime.Milliseconds / 100000.0f;

            Vector3 cameraPosition = camera.Position;
            Vector3 targetPos = camera.Target;
            //Matrix cameraRotation = Matrix.CreateRotationX(cameraAngles.X) * Matrix.CreateRotationZ(cameraAngles.Z);

            //    Matrix cameraRotation = Matrix.CreateRotationX(cameraAngles.X) * Matrix.CreateRotationZ(cameraAngles.Z);

            //    Vector3 targetPos = cameraPosition + Vector3.Transform(new Vector3(0, 1, 0), cameraRotation);
            //    Vector3 upVector = Vector3.Transform(new Vector3(0, 0, 1), cameraRotation);

            //    viewMatrix = Matrix.CreateLookAt(cameraPosition, targetPos, upVector);
            //    projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)this.Window.ClientBounds.Width / (float)this.Window.ClientBounds.Height, 1.0f, 1000.0f);

            //    float reflectionCamZCoord = -cameraPosition.Z + 2 * waterHeight;
            //    Vector3 reflectionCamPosition = new Vector3(cameraPosition.X, cameraPosition.Y, reflectionCamZCoord);

            //    float reflectionTargetZCoord = -targetPos.Z + 2 * waterHeight;
            //    Vector3 reflectionCamTarget = new Vector3(targetPos.X, targetPos.Y, reflectionTargetZCoord);

            //    Vector3 forwardVector = reflectionCamTarget - reflectionCamPosition;
            //    Vector3 sideVector = Vector3.Transform(new Vector3(1, 0, 0), cameraRotation);
            //    Vector3 reflectionCamUp = Vector3.Cross(sideVector, forwardVector);

            //    reflectionViewMatrix = Matrix.CreateLookAt(reflectionCamPosition, reflectionCamTarget, reflectionCamUp);



            float reflectionCamYCoord = -cameraPosition.Y + 2 * waterHeight;
            Vector3 reflectionCamPosition = new Vector3(cameraPosition.X, reflectionCamYCoord, cameraPosition.Z);
            //CameraComponent reflectionCam = new CameraComponent(game);
            //reflectionCam.Position = new Vector3(cameraPosition.X, reflectionCamYCoord, cameraPosition.Z);


            float reflectionTargetYCoord = -targetPos.Y + 2 * waterHeight;
            Vector3 reflectionCamTarget = new Vector3(targetPos.X, reflectionTargetYCoord, targetPos.Z);
            //reflectionCam.LookAt(new Vector3(targetPos.X, reflectionTargetYCoord, targetPos.Z));

            Vector3 forwardVector = reflectionCamTarget - reflectionCamPosition;
            Vector3 sideVector = Vector3.Transform(new Vector3(1, 0, 0), camera.Orientation);
            Vector3 reflectionCamUp = Vector3.Cross(sideVector, forwardVector);


            reflectionViewMatrix = Matrix.CreateLookAt(reflectionCamPosition, reflectionCamTarget, reflectionCamUp);
            //reflectionViewMatrix = reflectionCam.ViewMatrix;
            //reflectionCam.Dispose();
            //reflectionCam = null;


            if (drawRefraction)
            {
                DrawRefractionMap(camera);
            }
            if (drawReflection)
            {
                DrawReflectionMap(camera);
            }

            if (drawTerrain)
            {
                DrawTerrain(camera.ViewMatrix, camera);
            }
            if (drawSkyBox)
            {
                DrawSkyDome(camera.ViewMatrix, camera);
            }
            DrawWater(camera);


        }


        public Vector3 PickTerrain(Ray ray, Vector3 myPosition)
        {
            Vector3 result = new Vector3();
            for (int x = 0; x < WIDTH; x++)
                for (int y = 0; y < HEIGHT; y++)
                {
                    BoundingBox tmp = new BoundingBox(terrainVertices[x + y * WIDTH].Position, (terrainVertices[x + y * WIDTH].Position) + new Vector3(1f, 1f, 1f));

                    if (ray.Intersects(tmp) != null)
                    {

                        //float? rayIntersect = ray.Intersects(tmp);
                        //Vector3 ret = new Vector3();
                        //if (rayIntersect.HasValue)
                        //{
                        //    ret = ray.Position + ray.Direction * rayIntersect.Value;
                        //}
                        //return ret;

                        result = new Vector3(y, 0, x);
                    }
                }
            return result;

        }


    }
}
